package cn.kgc.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.kgc.dto.SearchParam;
import cn.kgc.dto.SearchResult;
import cn.kgc.entity.SkuEsModel;
import cn.kgc.mapper.SkuEsModelElasticsearchRepository;
import cn.kgc.service.EsSearchService;
import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.core.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * <p></p>
 *
 * @author 李孟鸠
 * @Date: 2022年12月13日9:55
 */
@Service("esSearchService")
@Slf4j
public class EsSearchServiceImpl implements EsSearchService {

    @Resource
    private SkuEsModelElasticsearchRepository  skuEsModelElasticsearchRepository;
    @Override
    public SearchResult search(SearchParam searchParam) {
        //分页查询条件
        PageRequest pageable =
                PageRequest.of(searchParam.getPageNum(), 20);
        //普通的查询条件
        BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery();
        //普通的查询条件
        //根据二级标题查询
        if (StringUtils.isNotBlank(searchParam.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("subTitle", searchParam.getKeyword()));
        }

        //根据分类的ID
        if (searchParam.getCategoryId()!=0){
            boolQueryBuilder.filter(QueryBuilders.termQuery("categoryId",searchParam.getCategoryId()));
        }

        if (CollectionUtil.isNotEmpty(searchParam.getBrandId())){
            for (Long aLong : searchParam.getBrandId()) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("brandId",aLong));
            }

        }

        //200_5000
        if (StringUtils.isNotBlank(searchParam.getSkuPrice())){
           String tempMinPrice= searchParam.getSkuPrice().split("_")[0];
            RangeQueryBuilder rangeQueryBuilder =
                    QueryBuilders.rangeQuery("skuPrice");
            long minPrice=0;
            if (StringUtils.isNotBlank(tempMinPrice)){
                minPrice=Long.parseLong(tempMinPrice);

           }

            long maxPrice=9999999;
            String tempMaxPrice=searchParam.getSkuPrice().split("_")[1];
            if (StringUtils.isNotBlank(tempMaxPrice)){
                maxPrice=Long.parseLong(tempMaxPrice);
            }
            rangeQueryBuilder.gte(minPrice).lte(maxPrice);
            boolQueryBuilder.filter(rangeQueryBuilder);
        }

        //是否有库存
        boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock",searchParam.isHasStock()));

        //属性的嵌套查询（属性的类型是Nested）
        if (CollectionUtil.isNotEmpty(searchParam.getAttrs())){
            //属性编号，属性的值  {属性编号 属性的值，属性编号_属性的值}
            for (String attr : searchParam.getAttrs()) {
                long attrId = Long.parseLong(attr.split("_")[0]);
                String attrValue=attr.split("_")[1];

                boolQueryBuilder.filter(
                        QueryBuilders.nestedQuery("attrList",
                                QueryBuilders.boolQuery()
                                        .filter(
                                                QueryBuilders.termQuery("attrList.attrId",attrId)).
                                        filter(
                                                QueryBuilders.termQuery("attrList.attrValue",attrValue)),
                                ScoreMode.None));
            }
        }

        //排序规则
        FieldSortBuilder fieldSortBuilder =
                SortBuilders.fieldSort(searchParam.getSort()).order(SortOrder.DESC);

        //聚合查询
       TermsAggregationBuilder brandAggregation=
               AggregationBuilders.terms("brand_id_aggs")
                       .field("brandId").size(10).subAggregation(
                               AggregationBuilders.terms("brand_name_aggs")
                                       .field("brandName").size(10)
                       );
       //属性的聚合
        NestedAggregationBuilder nested = AggregationBuilders.nested("attr_aggs", "attrList");

        nested.subAggregation(AggregationBuilders.terms("attr_id_aggs").field("attrList.attrId")
                .subAggregation(AggregationBuilders.terms("attr_name_aggs").field("attrList.attrName")
                        .subAggregation(AggregationBuilders.terms("attr_value_aggs").field("attrList.attrValue"))
                ));




        NativeSearchQuery searchQuery=new NativeSearchQueryBuilder()
                .withPageable(pageable).withSort(fieldSortBuilder).withQuery(boolQueryBuilder)
                .addAggregation(brandAggregation).addAggregation(nested).build();

        //执行查询操作
    AggregatedPage<SkuEsModel> aggregatedPage =
            (AggregatedPage<SkuEsModel>) skuEsModelElasticsearchRepository.search(searchQuery);

        SearchResult searchResult=new SearchResult();
        //总记录数
        long total = aggregatedPage.getTotalElements();
        //总页数
        long totalPages = aggregatedPage.getTotalPages();
        //当前页数据
        List<SkuEsModel> skuEsModelList = aggregatedPage.getContent();
        //获得聚合数据
        Terms terms =
                (Terms) aggregatedPage.getAggregations().getAsMap().get("brand_id_aggs");
        List<SearchResult.BrandVO>brandVOList=new ArrayList<>();

        for (Terms.Bucket bucket : terms.getBuckets()) {
            SearchResult.BrandVO brandVO=new SearchResult.BrandVO();
            long brandId = Long.parseLong(bucket.getKeyAsString());
            brandVO.setBrandId(brandId);
            //brand_id_aggs的子聚合
            Terms terms1 = (Terms) bucket.getAggregations().getAsMap().get("brand_name_aggs");
            for (Terms.Bucket terms1Bucket : terms1.getBuckets()) {
                String brandName = terms1Bucket.getKeyAsString();
                brandVO.setBrandName(brandName);
            }
            brandVOList.add(brandVO);
        }


        searchResult.setBrandVOList(brandVOList);
        searchResult.setTotal(total);
        searchResult.setTotalPages(totalPages);
        searchResult.setPageNum(searchParam.getPageNum());
        searchResult.setSkuEsModels(skuEsModelList);

        //todo 属性的聚合和分类的聚合
        Aggregation productAttrs=aggregatedPage.getAggregations().get("attr_aggs");
        List<SearchResult.AttrVo> attrVOList=new ArrayList<>();
        for (Terms.Bucket attr_id_aggs :
                ((ParsedLongTerms)((ParsedNested) productAttrs).getAggregations().get("attr_id_aggs")).getBuckets()) {
            SearchResult.AttrVo attrVO=new SearchResult.AttrVo();
            String idValue=  attr_id_aggs.getKeyAsString();
            attrVO.setAttrId(Long.parseLong(idValue));
            for (Terms.Bucket attr_name_aggs : ((ParsedStringTerms) (attr_id_aggs.getAggregations().get("attr_name_aggs")))
                    .getBuckets()) {
                String nameValue=attr_name_aggs.getKeyAsString();
                attrVO.setAttrName(nameValue);
                List<String> attrValues=new ArrayList<>();
                for (Terms.Bucket attr_value_aggs : ((ParsedStringTerms) attr_name_aggs.getAggregations().get("attr_value_aggs")).getBuckets()) {
                    String attrValue=attr_value_aggs.getKeyAsString();
                    attrValues.add(attrValue);
                }
                attrVO.setAttrValue(attrValues);
            }
            attrVOList.add(attrVO);
        }
        searchResult.setAttrVoList(attrVOList);

        return searchResult;

    }


}

